package com.xms.sdk.client;

import com.xms.core.data.Entity;
import com.xms.core.enums.AccessRightValue;
import com.xms.core.enums.EntityPermissionDepth;
import com.xms.core.exception.XmsException;
import com.xms.event.core.IEventPublisher;
import com.xms.organization.service.IBusinessUnitService;
import com.xms.schema.core.EntityMask;
import com.xms.schema.service.entity.IEntityFinderService;
import com.xms.sdk.core.OwnerTypes;
import com.xms.sdk.core.query.QueryBase;
import com.xms.sdk.core.query.QueryExpression;
import com.xms.sdk.extensions.EntityWrapper;
import com.xms.sdk.extensions.QueryExpressionExt;
import com.xms.security.entity.RoleEntityPermission;
import com.xms.security.identity.ICurrentUser;
import com.xms.security.service.dataauth.IPrincipalObjectAccessService;
import com.xms.security.service.dataauth.IRoleEntityPermissionService;
import com.xms.utils.CollectionUtil;
import org.springframework.beans.factory.annotation.Autowired;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * DataProviderBase
 * </p>
 *
 * @author migo
 * @since 2021/9/6
 */
public class DataProviderBase {
    protected IEntityFinderService _entityFinderService;
    protected IRoleEntityPermissionService _roleEntitypermissionService;
    protected IPrincipalObjectAccessService _principalObjectAccessService;
    protected IBusinessUnitService _businessUnitService;
    protected IEventPublisher _eventPublisher;
    protected ICurrentUser _currentUser;

    @Autowired
    public void DataProviderBase(IEntityFinderService entityFinderService
            , IRoleEntityPermissionService roleEntitypermissionService
            , IPrincipalObjectAccessService principalObjectAccessService
            , IBusinessUnitService businessUnitService
            , IEventPublisher eventPublisher
            , ICurrentUser currentUser) {
        _entityFinderService = entityFinderService;
        _roleEntitypermissionService = roleEntitypermissionService;
        _principalObjectAccessService = principalObjectAccessService;
        _businessUnitService = businessUnitService;
        _eventPublisher = eventPublisher;
        _currentUser = currentUser;
    }

    protected com.xms.schema.entity.Entity getEntityMetaData(String entityName) throws XmsException {
        com.xms.schema.entity.Entity entityMetadata = _entityFinderService.getByName(entityName);
        if (entityMetadata == null) {
            throw new XmsException(String.format("实体 “%s” 不存在", entityName));
        }
        return entityMetadata;
    }

    protected List<RoleEntityPermission> getUserEntityPermissions(QueryBase q, AccessRightValue access) throws XmsException {
        //get entity permissions
        if (_currentUser.isAdministrator())
            return null;
        List<UUID> rolesId = _currentUser.getRoles();
        if (CollectionUtil.isEmpty(rolesId)) {
            onException("用户没有分配角色");
        }
        List<String> entityNames = q instanceof QueryExpression ? QueryExpressionExt.getAllEntityNames((QueryExpression) q, null) : new ArrayList<String>() {
            {
                add(q.EntityName);
            }
        };
        List<UUID> entIds = _entityFinderService.getByNames(entityNames).stream().map(x -> x.getEntityid()).collect(Collectors.toList());
        return _roleEntitypermissionService.getRolePermissions(entIds, rolesId, access);
    }

    /**
     * 异常发生时执行的方法
     * @param e
     * @return
     * @throws XmsException
     */
    public boolean onException(Exception e) throws XmsException {
        e.printStackTrace();
        throw new XmsException(e.getMessage());
    }

    public boolean onException(String message) throws XmsException {
        throw new XmsException(message);
    }

    /**
     * 校验实体权限
     *
     * @param entity
     * @param access
     * @param entityMetadata
     * @throws XmsException
     * @throws SQLException
     */
    protected void verifyEntityPermission(com.xms.core.data.Entity entity, AccessRightValue access, com.xms.schema.entity.Entity entityMetadata) throws XmsException, SQLException {
        entityMetadata = entityMetadata == null ? getEntityMetaData(entity.Name) : entityMetadata;
        //authorization disabled or user in administrator group
        if (!entityMetadata.getAuthorizationenabled() || _currentUser.isAdministrator()) {
            return;
        }

        boolean hasPermission = false;
        //operation permission
        RoleEntityPermission roleEntityPermission = _roleEntitypermissionService.getUserPermission(entity.Name, _currentUser.getUser().SystemUserId, access);
        //permission depth
        String depth = "none";
        if (roleEntityPermission != null) {
            Entity data = EntityWrapper.unWrapAttributeValue(entity);
            if (entityMetadata.getEntitymask() == EntityMask.Organization.value()) {
                UUID b = data.getUUIDValue("organizationid");
                hasPermission = (roleEntityPermission.getAccessRightsMask() != EntityPermissionDepth.None && this._currentUser.getUser().OrganizationId.equals(b));
            } else {
                int ownerIdType = data.getIntValue("owneridtype");
                //full
                if (roleEntityPermission.getAccessRightsMask() == EntityPermissionDepth.Organization) {
                    hasPermission = true;
                } else if (ownerIdType == (int) OwnerTypes.SystemUser) {
                    //basic
                    if (roleEntityPermission.getAccessRightsMask() == EntityPermissionDepth.Self) {
                        hasPermission = data.getUUIDValue("ownerid").equals(this._currentUser.getUser().SystemUserId);
                    }
                    //local
                    else if (roleEntityPermission.getAccessRightsMask() == EntityPermissionDepth.BusinessUnit) {
                        UUID b = data.getUUIDValue("owningbusinessunit");
                        hasPermission = this._currentUser.getUser().BusinessUnitId.equals(b);
                    }
                    //deep
                    else if (roleEntityPermission.getAccessRightsMask() == EntityPermissionDepth.BusinessUnitAndChild) {
                        UUID b = data.getUUIDValue("owningbusinessunit");
                        hasPermission = _businessUnitService.isChild(this._currentUser.getUser().BusinessUnitId, b);
                    }
                } else if (ownerIdType == (int) OwnerTypes.Team) {
                    //basic
                    if (roleEntityPermission.getAccessRightsMask() == EntityPermissionDepth.Self) {
                        hasPermission = data.getUUIDValue("ownerid").equals(this._currentUser.getUser().SystemUserId);
                    }
                    //local
                    else if (roleEntityPermission.getAccessRightsMask() == EntityPermissionDepth.BusinessUnit) {
                        UUID b = data.getUUIDValue("owningbusinessunit");
                        hasPermission = this._currentUser.getUser().BusinessUnitId.equals(b);
                    }
                    //deep
                    else if (roleEntityPermission.getAccessRightsMask() == EntityPermissionDepth.BusinessUnitAndChild) {
                        UUID b = data.getUUIDValue("owningbusinessunit");
                        hasPermission = _businessUnitService.isChild(this._currentUser.getUser().BusinessUnitId, b);
                    }
                }
            }
            //depth = roleEntityPermission.AccessRightsMask.toString();
        }
        //shared permission
        /*if (!hasPermission)
        {
            var objectId = entity.getIdValue();
            var poa = _principalObjectAccessService.Find(n => n.ObjectId == objectId && n.AccessRightsMask == access);
            hasPermission = poa != null;
        }*/
        if (!hasPermission) {
            onException(String.format("没有 “%s” 的 “%s” 权限", entityMetadata.getLocalizedname(), access.text()));
        }
    }
}
